;; =============================================================================
;; this module provides print-c methods for serializing statement entries to
;; C code

(in-package :oali.core)

;; =============================================================================
;; introduces generic signature
(defgeneric print-c (statement stream))

;; =============================================================================
;; proxy type
(defmethod print-c ((statement p-type-proxy) stream)
  (print-c (proxy-type statement) stream))

;; =============================================================================
;; builtin type
(defmethod print-c ((statement p-type-builtin) stream)
  (write-string (name statement) stream))


;; =============================================================================
;; qualified type
(defmethod print-c ((statement p-qualified-type) stream)
  (write-string (case (qualifier statement)
		  (signed "signed")
		  (unsigned "unsigned")
		  (t (error (format nil "unknown qualifier ~a" (qualifier statement)))))
		stream)
  (write-char #\Space stream)
  (print-c (inferior-type statement) stream))

;; =============================================================================
;; complex type member
(defmethod print-c ((statement p-complex-type-member) stream)
  (print-c (member-type statement) stream)
  (write-char #\Space stream)
  (write-string (name statement) stream)
  (write-char #\; stream)
  (write-char #\Newline stream))

;; =============================================================================
;; struct/union type
(defmethod print-c ((statement p-type-complex) stream)
  (let ((align (align statement))
	(is-union (is-union statement))
	(members (members statement)))
    ; data alignment must be >0 & <= 256 (or null)
    (check-type align (or null (integer 1 256)))
    (check-type is-union boolean)	; only t/nil are accepted
    (check-type members cons)		; members shall always be a list

    ;; initial alignment pragma
    (if align
	(progn
	  (write-string "#pragma pack(push, " stream)
	  (print align stream)
	  (write-char #\( stream)
	  (write-char #\Newline stream)))

    ;; struct NAME\n{\n
    (format stream "~a ~a~%{~%"
	    (if is-union "union" "struct")
	    (name statement))
    
    ;; members
    (dolist (member members)
      (print-c member stream))

    ;; closing paren with semicolon
    (write-string "};" stream)

    ;; final alignment pragma and newline
    (if align (write-string "#pragma pack(pop)" stream))
    (write-char #\Newline stream)))

;; =============================================================================
;; pointer type
(defmethod print-c ((statement p-type-pointer) stream)
  (let ((pointee (pointee-type statement)))
    (print-c pointee stream)
    (write-string (if (typep pointee 'p-type-pointer) "*" " *") stream)))

